package org.oschina.api.comment.service;

import java.util.List;
import org.oschina.Config;
import org.oschina.Constants;
import org.oschina.Message;
import org.oschina.Module;
import org.oschina.ResultUtil;
import org.oschina.api.BaseService;
import org.oschina.api.blog.blog.service.BlogService;
import org.oschina.api.comment.CommentCatalog;
import org.oschina.api.comment.CommentType;
import org.oschina.api.comment.dao.CommentDAO;
import org.oschina.api.comment.model.Comment;
import org.oschina.api.comment.vo.CommentVo;
import org.oschina.api.discuss.discuss.service.DiscussService;
import org.oschina.api.dongtan.service.DongtanService;
import org.oschina.api.index.service.IndexService;
import org.oschina.api.manage.config.service.ConfigService;
import org.oschina.api.manage.module.ModuleType;
import org.oschina.api.manage.module.vo.ModuleVo;
import org.oschina.api.report.ReportType;
import org.oschina.api.report.service.ReportService;
import org.oschina.api.report.vo.ReportVo;
import org.oschina.api.user.role.service.UserRoleService;
import org.oschina.api.user.user.model.User;
import org.oschina.api.user.user.service.UserService;
import org.oschina.api.user.user.vo.UserVo;
import org.oschina.bean.Pager;
import org.oschina.bean.Result;
import org.oschina.handler.validator.annotation.Validate;
import org.oschina.handler.validator.annotation.ValidateField;
import org.oschina.handler.validator.filter.HtmlCleanFileter;
import org.oschina.plugin.PluginHelper;
import org.oschina.plugin.PluginType;
import org.oschina.security.AuthenticationException;
import org.oschina.security.ISecurity;
import org.oschina.security.annotation.Require;
import org.oschina.util.DateUtil;
import org.oschina.util.ListUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class CommentService extends BaseService {

	@Autowired
	private CommentDAO commentDAO;
	@Autowired
	private IndexService indexService;
	@Autowired
	private UserRoleService userRoleService;
	@Autowired
	private UserService userService;
	@Autowired
	private PluginHelper pluginHelper;
	@Autowired
	private ConfigService configService;
	@Autowired
	private ISecurity security;
	@Autowired
	private ReportService reportService;
	@Autowired
	private DiscussService discussService;
	@Autowired
	private DongtanService dongtanService;
	@Autowired
	private BlogService blogService;
	
	/**
	 * 举报
	 * @param id
	 * @param content
	 * @return
	 */
	@Require(authorization=Module.MODULE_57)
	public Result createReport(int id,String content)
	{
		CommentVo commentVo=_findVoById(id);
		if(commentVo==null || !_isSimple(commentVo))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		Result result=reportService.create(id, ReportType.COMMENT, content);
		
		if(result.isSuccess())
		{
			switch (commentVo.getCatalog())
			{
				case CommentCatalog.DISCUSS:
				{
					discussService._reportComment(commentVo.getRelevance());
					break;
				}
				case CommentCatalog.DONGTAN:
				{
					dongtanService._reportComment(commentVo.getRelevance());
					break;
				}
				case CommentCatalog.BLOG:
				{
					blogService._reportComment(commentVo.getRelevance());
					break;
				}
			}
			
			if(_isQuote(commentVo))
			{
				_updateQuoteCount_minus(commentVo.getQuote());
			}
			
			_setReport(commentVo);
		}
		
		return result;
	}
	
	/**
	 * 返回举报详细信息
	 * @param id
	 * @return
	 */
	@Require(authorization=Module.MODULE_56)
	public ReportVo findReportConcrete(int id)
	{
		return reportService.findVoByMajorAndType(id, ReportType.COMMENT);
	}
	
	/**
	 * 返回举报
	 * @param pn
	 * @return
	 */
	@Require(authorization=Module.MODULE_56)
	public Pager<CommentVo> findReport(int pn)
	{
		Pager<CommentVo> pager=new Pager(pn,_getCountByType(CommentType.REPORT),_getPageCount(),null);
		if(pager.getData_sum()>0)
			pager.setData(_findVoByType(CommentType.REPORT, pager.getStart(), pager.getPage_count()));
		
		return pager;
	}
	
	/**
	 * 返回删除
	 * @param pn
	 * @return
	 */
	@Require(authorization=Module.MODULE_58)
	public Pager<CommentVo> findDelete(int pn)
	{
		Pager<CommentVo> pager=new Pager(pn,_getCountByType(CommentType.DELETE),_getPageCount(),null);
		if(pager.getData_sum()>0)
			pager.setData(_findVoByType(CommentType.DELETE, pager.getStart(), pager.getPage_count()));
		
		return pager;
	}
	
	/**
	 * 恢复已删除
	 * @param id
	 * @return
	 */
	@Require
	public Result recoverDelete(int id)
	{
		CommentVo commentVo=_findVoById(id);
		if(commentVo==null || (!_isDelete(commentVo) && !_isReport(commentVo)))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		if(_isDelete(commentVo) && !security.require(new String[]{Module.MODULE_58}, getToken(), false))
			throw new AuthenticationException();
		
		if(_isReport(commentVo))
		{
			if(!security.require(new String[]{Module.MODULE_56}, getToken(), false))
				throw new AuthenticationException();
			else
				reportService.deleteByMajorAndType(id, ReportType.COMMENT);
		}
		else
		{
			switch (commentVo.getCatalog())
			{
				case CommentCatalog.DISCUSS:
				{
					discussService._recoverComment(commentVo.getRelevance());
					break;
				}
				case CommentCatalog.DONGTAN:
				{
					dongtanService._recoverComment(commentVo.getRelevance());
					break;
				}
				case CommentCatalog.BLOG:
				{
					blogService._recoverComment(commentVo.getRelevance());
					break;
				}
			}
		}
		
		if(_isQuote(commentVo))
		{
			_updateQuoteCount_plus(commentVo.getQuote());
		}
		
		_setSimple(commentVo);
		return ResultUtil.getSuccess(Message.UPDATE_SUCCESS);
	}
	
	/**
	 * 返回引用
	 * @param quote
	 * @param pn
	 * @return
	 */
	public Pager<CommentVo> findByQuoteAndType(int quote,int pn)
	{
		CommentVo quoteComment=_findVoById(quote);
		
		if(quoteComment==null || !_isSimple(quoteComment))
			return null;
		
		Pager<CommentVo> pager=new Pager(pn,quoteComment.getQuote_count(),_getQuotePageCount(),null);
		if(pager.getData_sum()>0)
		{
			User user=userService.getAuthenticationInfo(getToken());
			List<CommentVo> result=_findVoByQuoteAndType(quote,CommentType.SIMPLE, pager.getStart(), pager.getPage_count());
			if(user!=null && !result.isEmpty())
			{
				List<ModuleVo> module=userRoleService._findVoByRoleAndType(user, ModuleType.MODULE_18);
				List<ModuleVo> authorModule=null;
				for(CommentVo commentVo:result)
				{
					if(_isAuthor(user,commentVo))
					{
						if(authorModule==null)
						{
							authorModule=userRoleService._findVoByRoleAndType(user, ModuleType.MODULE_17);
							authorModule.addAll(module);
							authorModule=ListUtil.removeRepeat(authorModule);
						}
						commentVo.setModule(authorModule);
					}
					else
						commentVo.setModule(module);
				}
			}
			pager.setData(result);
		}
		return pager;
	}
	
	/**
	 * 根据评论ID返回
	 * @param commentId
	 * @param pn
	 * @return
	 */
	public Pager<CommentVo> findByCommentId(int commentId,int pn)
	{
		Pager<CommentVo> pager=new Pager(pn,_getCountByCommentIdAndType(commentId,CommentType.SIMPLE),_getPageCount(),null);
		if(pager.getData_sum()>0)
		{
			User user=userService.getAuthenticationInfo(getToken());
			List<CommentVo> result=_findByCommentIdAndType(commentId,CommentType.SIMPLE, pager.getStart(), pager.getPage_count());
			if(user!=null && !result.isEmpty())
			{
				List<ModuleVo> module=userRoleService._findVoByRoleAndType(user, ModuleType.MODULE_18);
				List<ModuleVo> authorModule=null;
				for(CommentVo commentVo:result)
				{
					if(_isAuthor(user,commentVo))
					{
						if(authorModule==null)
						{
							authorModule=userRoleService._findVoByRoleAndType(user, ModuleType.MODULE_17);
							authorModule.addAll(module);
							authorModule=ListUtil.removeRepeat(authorModule);
						}
						commentVo.setModule(authorModule);
					}
					else
						commentVo.setModule(module);
				}
			}
			pager.setData(result);
		}
		return pager;
	}
	
	/**
	 * 编辑
	 * @param commentVo
	 * @return
	 */
	@Require
	public Result edit(Comment comment)
	{
		CommentVo commentVo=_findVoById(comment.getId());
		if(commentVo==null || !_isSimple(commentVo))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		_require(getToken(),commentVo,new String[]{Module.MODULE_50},new String[]{Module.MODULE_49});
		
		_edit(comment);
		return ResultUtil.getSuccess(commentVo);
	}
	
	/**
	 * 删除
	 * @param commentVo
	 * @return
	 */
	@Require
	public Result delete(int id)
	{
		CommentVo commentVo=_findVoById(id);
		if(commentVo==null || (!_isSimple(commentVo) && !_isReport(commentVo)))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		if(_isSimple(commentVo))
		{
			_require(getToken(),commentVo,new String[]{Module.MODULE_52},new String[]{Module.MODULE_51});
			switch (commentVo.getCatalog())
			{
				case CommentCatalog.DISCUSS:
				{
					discussService._deleteComment(commentVo.getRelevance());
					break;
				}
				case CommentCatalog.DONGTAN:
				{
					dongtanService._deleteComment(commentVo.getRelevance());
					break;
				}
				case CommentCatalog.BLOG:
				{
					blogService._deleteComment(commentVo.getRelevance());
					break;
				}
			}
		}
		else if(_isReport(commentVo))
		{
			if(!security.require(new String[]{Module.MODULE_56}, getToken(), false))
				throw new AuthenticationException();
			else
				reportService.deleteByMajorAndType(id, ReportType.COMMENT);
		}
		
		if(_isQuote(commentVo))
		{
			_updateQuoteCount_minus(commentVo.getQuote());
		}
		
		_setDelete(commentVo);
		return ResultUtil.getSuccess(Message.DELETE_SUCCESS);
	}
	
	/**
	 * 创建
	 * @param relevance
	 * @param commentId
	 * @param content
	 * @param catalog
	 * @param quote
	 * @return
	 */
	@Validate
	@Require(authorization=Module.MODULE_8)
	public Result _create
	(
		@Validate(validateField=@ValidateField(validateValue=true,min=1)) int relevance,
		@Validate(validateField=@ValidateField(validateValue=true,min=1)) int commentId,
		@Validate(validateField=@ValidateField(validateValue=true,filter={HtmlCleanFileter.class},min=5,max=10000)) String content,
		@Validate(validateField=@ValidateField(validateValue=true,min=0)) int quote,
		@Validate(validateField=@ValidateField(validateValue=true,min=1)) int catalog
	)
	{
		if(quote!=0)
		{
			CommentVo commentVo=_findVoById(quote);
			if(commentVo==null || _isQuote(commentVo) || !commentVo.getRelevance().equals(relevance))
				return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		}
		
		UserVo user=userService.getVo(getToken());
		Comment comment=new Comment();
		comment.setId(_getCommentIndex());
		comment.setMajor(commentId);
		comment.setRelevance(relevance);
		comment.setContent(content);
		comment.setAuthor(user);
		comment.setCatalog(catalog);
		comment.setType(CommentType.SIMPLE);
		comment.setFloor((quote!=0?0:_getMaxFloorByCommentId(commentId)+1));
		comment.setQuote(quote);
		comment.setQuote_count(0);
		comment.setIp(getIp());
		comment.setCreate_time(DateUtil.now());
		
		pluginHelper.execute(PluginType.COMMENT_CREATE_BEFORE, comment);
		_create(comment);
		pluginHelper.execute(PluginType.COMMENT_CREATE_AFTER, comment);
		
		if(quote!=0)
		{
			_updateQuoteCount_plus(quote);
		}
		
		return ResultUtil.getSuccess(comment);
	}
	
	/**
	 * 更新引用数量
	 * @param id
	 */
	private void _updateQuoteCount_plus(int id)
	{
		_updateQuoteCount(id,1);
	}
	
	/**
	 * 更新引用数量
	 * @param id
	 */
	private void _updateQuoteCount_minus(int id)
	{
		_updateQuoteCount(id,-1);
	}
	
	/**
	 * 更新引用数量
	 * @param id
	 * @param count
	 */
	private void _updateQuoteCount(int id,int count)
	{
		commentDAO.updateQuoteCount(id, count);
	}
	
	/**
	 * 根据类型返回
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	private List<CommentVo> _findVoByType(int type,int first,int max)
	{
		return commentDAO.findVoByType(type, first, max);
	}
	
	/**
	 * 根据类型返回数量
	 * @param type
	 * @return
	 */
	private int _getCountByType(int type)
	{
		return commentDAO.getCountByType(type);
	}
	
	/**
	 * 根据引用返回
	 * @param quote
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	public List<CommentVo> _findVoByQuoteAndType(int quote,int type,int first,int max)
	{
		return commentDAO.findVoByQuoteAndType(quote, type, first, max);
	}
	
	/**
	 * 根据评论ID和类型返回
	 * @param commentId
	 * @param first
	 * @param max
	 * @return
	 */
	private List<CommentVo> _findByCommentIdAndType(int commentId,int type,int first,int max)
	{
		return commentDAO.findByCommentIdAndType(commentId, type,first, max);
	}
	
	/**
	 * 根据评论ID和类型返回数量
	 * @param commentId
	 * @param type
	 * @return
	 */
	private int _getCountByCommentIdAndType(int commentId,int type)
	{
		return commentDAO.getCountByCommentIdAndType(commentId,type);
	}
	
	/**
	 * 根据评论ID返回层数
	 * @param id
	 * @return
	 */
	private int _getMaxFloorByCommentId(int id)
	{
		return commentDAO.getMaxFloorByCommentId(id);
	}
	
	/**
	 * 更新类型
	 * @param id
	 * @param type
	 * @return
	 */
	private int _updateType(int id,int type)
	{
		 return commentDAO.updateType(id, type);
	}
	
	/**
	 * 编辑
	 * @param comment
	 * @return
	 */
	private int _edit(Comment comment)
	{
		return commentDAO.edit(comment);
	}
	
	/**
	 * 创建
	 * @param comment
	 * @return
	 */
	private Comment _create(Comment comment)
	{
		return commentDAO.create(comment);
	}
	
	private CommentVo _findVoById(int id)
	{
		return commentDAO.findVoById(id);
	}
	
	private boolean _isAuthor(User user,CommentVo comment)
	{
		return comment.getAuthor().getId().equals(user.getId());
	}
	
	private boolean _isSimple(CommentVo commentVo)
	{
		return commentVo.getType().equals(CommentType.SIMPLE);
	}
	
	private boolean _isCheck(CommentVo commentVo)
	{
		return commentVo.getType().equals(CommentType.CHECK);
	}
	
	private boolean _isDelete(CommentVo commentVo)
	{
		return commentVo.getType().equals(CommentType.DELETE);
	}
	
	private boolean _isReport(CommentVo commentVo)
	{
		return commentVo.getType().equals(CommentType.REPORT);
	}
	
	private boolean _isQuote(CommentVo commentVo)
	{
		return (commentVo.getQuote().equals(0)?false:true);
	}
	
	private void _setSimple(CommentVo commentVo)
	{
		_updateType(commentVo.getId(),CommentType.SIMPLE);
	}
	
	private void _setCheck(CommentVo commentVo)
	{
		_updateType(commentVo.getId(),CommentType.CHECK);
	}
	
	private void _setDelete(CommentVo commentVo)
	{
		_updateType(commentVo.getId(),CommentType.DELETE);
	}
	
	private void _setReport(CommentVo commentVo)
	{
		_updateType(commentVo.getId(),CommentType.REPORT);
	}
	
	/**
	 * 返回评论最新索引
	 * @return
	 */
	public int _getIndex()
	{
		return indexService.getMajorById(Constants.INDEX_COMMENT_LIST);
	}
	
	private int _getCommentIndex()
	{
		return indexService.getMajorById(Constants.INDEX_COMMENT);
	}
	
	private int _getPageCount()
	{
		return (Integer) configService.getValueById(Config.CONFIG_1, Integer.class);
	}
	
	private int _getQuotePageCount()
	{
		return (Integer) configService.getValueById(Config.CONFIG_31, Integer.class);
	}
	
	/**
	 * 验证
	 * @param token 令牌
	 * @param commentVo 评论
	 * @param authority 主权限
	 * @param authorityOr
	 * @param authorAuthority 作者权限
	 * @param authorAuthorityOr
	 */
	private void _require(String token,CommentVo commentVo,String authority[],String authorAuthority[])
	{
		_require(token,commentVo,authority,false,authorAuthority,false);
	}
	private void _require(String token,CommentVo commentVo,String authority[],boolean authorityOr,String authorAuthority[],boolean authorAuthorityOr)
	{
		if(!security.require(authority, token, authorityOr))
		{
			User user=userService.getAuthenticationInfo(token);
			if(!_isAuthor(user,commentVo) || !security.require(authorAuthority, token, authorAuthorityOr))
				throw new AuthenticationException();
		}
	}
}